package org.pettyfox.home.assistant.mbd;

import cn.hutool.core.net.NetUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;

/**
 * 通过局域网ip判断成员是否在家，并通知到home assistant
 *
 * @author pettyfox
 * @version 1.0
 */
@Slf4j
public class DaemonMemberForLan {
    public static void main(String[] args) {
        log.info("DaemonMemberForLan start");
        if (new DaemonMemberForLan().startCheckMember()) {
            log.info("DaemonMemberForLan started");
            try {
                new CountDownLatch(1).await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            log.info("DaemonMemberForLan failed");

        }
    }

    private boolean startCheckMember() {
        //ping地址
        String ips = System.getenv("checkIps");
        String haToken = System.getenv("haToken");
        String haUrl = System.getenv("haUrl");
        //成员弱是否在家
        String haWeekHasMemberEntityId = System.getenv("haWeekHasMemberEntityId");
        //成员离开时间大于此，才判定为无人在家,单位秒,建议十分钟
        int memberLevelTime = Integer.parseInt(Optional.ofNullable(System.getenv("memberLevelTimeSec")).orElse("0"));
        if (StrUtil.isBlank(haToken)) {
            log.error("please config haToken");
            return false;
        }
        if (StrUtil.isBlank(haUrl)) {
            log.error("please config haUrl");
            return false;
        }
        if (StrUtil.isBlank(haWeekHasMemberEntityId)) {
            log.error("please config haWeekHasMemberEntityId");
            return false;
        }
        if (StrUtil.isBlank(ips)) {
            log.error("please config checkIps for env");
            return false;
        }
        List<String> ipList = filterIpFormat(ips.split(","));
        if (ipList.isEmpty()) {
            log.error("config checkIps error." + ips);
            return false;
        }
        ThreadUtil.newThread(() -> {
            boolean hasMember = false;
            long lastHasMember = 0;
            boolean homeAssistantSwitchState = false;
            //是否与ha状态初始保持一致
            boolean isHaInitSync = false;
            while (true) {
                if (hasMember(ipList)) {
                    //有人在家
                    hasMember = true;
                    lastHasMember = System.currentTimeMillis();
                } else {
                    //无人在家
                    if (System.currentTimeMillis() - lastHasMember > memberLevelTime*1000) {
                        hasMember = false;
                    }
                }
                if (hasMember != homeAssistantSwitchState || !isHaInitSync) {
                    //发送开关状态同步指令
                    homeAssistantSwitchState = syncState2Ha(haUrl, haToken, haWeekHasMemberEntityId, hasMember);
                    if (hasMember == homeAssistantSwitchState) {
                        isHaInitSync = true;
                    }
                }


                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "check-member-t").start();
        return true;
    }

    private List<String> filterIpFormat(String[] ipList) {
        List<String> ips = new ArrayList<>();
        for (String ip : ipList) {
            if (NetUtil.isInnerIP(ip)) {
                ips.add(ip);
            }
        }
        return ips;
    }

    public boolean hasMember(List<String> ipList) {
        for (String ip : ipList) {
            try {
                if (NetUtil.ping(ip, 1000)) {
                    return true;
                }
            } catch (Exception e) {
                log.error("ping error", e);
            }
        }
        return false;
    }

    private boolean syncState2Ha(String url, String token, String entityId, boolean state) {
        log.info("sync ha state,url:{},entityId:{},state:{},token:{}", url, entityId, state, token);
        String pState = state ? "on" : "off";
        JSONObject post = new JSONObject();
        post.put("state", pState);
        try {
            String rep =  HttpRequest.post(url+"/api/states/"+entityId).header("Authorization","Bearer "+token)
                    .body(post.toJSONString())
                    .timeout(5000).execute().body();
            JSONObject data = JSON.parseObject(rep);
            if (pState.equals(data.getString("state"))) {
                log.info("ha api response success:{}",rep);
                return state;
            } else {
                log.warn("ha api response:{}",rep);
                return !state;
            }
        } catch (Exception e) {
            log.error("sync ha error", e);
        }
        return !state;
    }
}
